#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN_PATH 1024
#define LEN_LINE 1024
int ustrncmp_chars(const char* s, int size, char chs[], int n)
{
    int ret = 0;
    int i; 
    int matched;

    while(*s != '\0' && size-->0) {
        matched = 0;
        for(i=0; i<n; i++) {
            if(*s == chs[i]) {
                matched = 1;
                break;
            }
        }

        if(0 == matched) {
            ret = -1;
            break;
        }
    }

    return ret;
}


#define USTRING_LEN_CHARS_BLANK 2
char kchar_blank[USTRING_LEN_CHARS_BLANK] = {' ', '\t'};


#define USTRING_LEN_CHARS_BLANK_MAX 4
char kchar_blank_max[USTRING_LEN_CHARS_BLANK_MAX] = {' ', '\t', '\r', '\n'};


int ustrcmp_blank(const char* s)
{
    return ustrncmp_chars(s, strlen(s), kchar_blank, USTRING_LEN_CHARS_BLANK);
}


int ustrncmp_blank(const char* s, int size)
{
    return ustrncmp_chars(s, size, kchar_blank, USTRING_LEN_CHARS_BLANK);
}


size_t ustrlen_without_crlf(const char* s)
{
    size_t size = strlen(s);
    if(size > 2 && s[size-2] == '\r' && s[size-1] == '\n') {
        size -= 2 ;
    }
    else if(size > 1 && s[size-1] == '\n') {
        size -= 1 ;
    }

    return size;
}


int mktmpname(char* dest, size_t size, const char* src)
{
    int ret = 0;
    snprintf(dest, size, "tmp.%s", src);
    size_t len = strlen(dest);
    int i;
    for(i=0; i<len; i++) {
        if((dest[i] >= 'a' && dest[i] <= 'z') || (dest[i] >= 'A' && dest[i] <= 'Z')) {
            continue;
        }

        dest[i] = '-';
    }

    return ret;
}


int ubacktrace_add(const char* path)
{
    int ret = 0;

    FILE* fr = fopen(path, "r");
    if(NULL == fr) {
        fprintf(stderr, "open source file error.\n");
        ret = -1;
        return ret;
    }

    char path_write[LEN_PATH];
    mktmpname(path_write, LEN_PATH, path);
    FILE* fw = fopen(path_write, "w");
    if(NULL == fw) {
        fprintf(stderr, "open tmp source file error.\n");
        fclose(fr);
        ret = -1;
        return ret;
    }

    char line[LEN_LINE];
    char line_tmp[LEN_LINE];
    while(NULL != fgets(line, LEN_LINE, fr)) {
        size_t size_line = ustrlen_without_crlf(line);
        if(line[0] == '{' && 0 == ustrncmp_blank(line+1, size_line-1)) {
            long n_offset = ftell(fr);
            /* find match } . */
            int matched = 0;
            while(NULL != fgets(line_tmp, LEN_LINE, fr)) {
                size_t size_tmp = ustrlen_without_crlf(line_tmp);
                if(line_tmp[0] == '{' 
                        && 0 == ustrncmp_blank(line_tmp+1, size_tmp-1)) {
                    break;
                }

                if(line_tmp[0] == '}' 
                        && 0 == ustrncmp_blank(line_tmp+1, size_tmp-1)) {
                    matched = 1;
                    break;
                }
            }

            fseek(fr, n_offset, SEEK_SET);
            if(matched) {
                fputs("{__enter_", fw);
                fputs(line+1, fw);
            }
            else {
                fputs(line, fw);
            }
        }
        else {
            /* replace return to __return_. */
            char* tmp = strstr(line, "return");
            if(NULL != tmp 
                    && (tmp == line || *(tmp-1) == ' ' || *(tmp-1) == '\t')
                    && (*(tmp+6) == ' ' || *(tmp+6) == '\t')) {

                if(line < tmp) {
                    fwrite(line, 1, tmp-line, fw);
                }
                fputs("__return_", fw);
                fputs(tmp+6, fw);
            }
            else {
                fputs(line, fw);
            }
        }
    }

    fclose(fr);
    fclose(fw);

    rename(path_write, path);

    return ret;
}


int main(int argc, char* argv[])
{
    if(argc != 2) {
        fprintf(stderr, "usage:./devtool-ubacktrace files-from.\n");
        exit(1);
    }

    char path[LEN_PATH];
    FILE* ff = fopen(argv[1], "r");
    if(NULL == ff) {
        fprintf(stderr, "arg files-from read error.\n");
        exit(1); 
    }

    int ret;
    char* tmp;
    while(NULL != fgets(path, LEN_PATH, ff)) {
        if(NULL != (tmp = strchr(path, '\r')) || NULL != (tmp = strchr(path, '\n'))) {
            *tmp = '\0';
        }

        ret = ubacktrace_add(path);
        if(-1 == ret) {
            fprintf(stderr, "%s add ubacktrace error.\n", path);
        }
        else {

        }
    }
    fclose(ff);

    return 0;
}














